Skip to main content

第 2 章:K8S 最基本的單位 Pods

什麼是 Pods

  • Pod 是 K8S 調度的最小單位
  • Pod 中的容器共享網路與 Namespace (具有相同的 IP 位址)
  • Pod 中的容器共用資源(例如磁碟區)

Pod 的 YAML 範例

sample.yml
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
# Label
labels:
disk: ssd
run: web
name: web
# Security Context
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
# init Containers
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
volumeMounts:
- name: config-vol
mountPath: /etc/config
securityContext:
capabilities:
## 允許設定 SYS_TIME
add: ["SYS_TIME"]
containers:
- name: nginx-container
image: nginx:latest
volumeMounts:
- name: pvolumn
mountPath: /
env:
- name: "name"
value: "beta"
containers:
- name: hello
image: busybox:1.28
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
livenessProbe:
exec:
command:
- 'true'
readinessProbe:
exec:
command:
- sh
- -c
- 'wget -T2 -O- http://service-am-i-ready:80'
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
volumes:
# ConfigMap
- name: config-vol
configMap:
name: log-config
items:
- key: log_level
path: log_level
# Pesistent Volume
- name: webcontent
persistentVolumeClaim:
claimName: pvc-nfs
# Secret Volume
- name: secret-volume
secret:
secretName: dotfile-secret
# EmptyDir
- name: cache-volume
emptyDir:
sizeLimit: {}
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- antarctica-east1
- antarctica-west1
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value

建立 Pods 的兩種模式

命令式管理 Imperative Management

  • kubectl create / kubectl run
    • 直接透過命令創建,替換或刪除的內容
    • 先刪除所有現有的東西,重新根據配置文件(YAML)生成新的
    • 用同一個配置文件重複創建會失敗,只能創建一次
  • 範例
kubectl run web --image=nginx

聲明式管理 Declarative Management

  • kubectl apply
    • 根據配置文件裡面列出来的内容來生成目標環境
    • 若需要調整環境,只需要調製配置文件
    • 可以透過同一個配置文件重複創建多個環境
  • 範例
nginx.yml
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
containers:
- name: nginx-container
image: nginx:latest
ports:
- containerPort: 80
kubectl apply -f nginx.yml
pod/web created

運行 1 個 Pod 包含多個容器

以下為一個最簡單的範例,這個 pod 同時包含兩個容器 containers:nginx 與 busybox

my-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: nginx
image: nginx
- name: client
image: busybox
command:
- sh
- -c
- "sleep 1000000"
kubectl create -f my-pod.yml
kubectl get pod
NAME READY STATUS RESTARTS AGE
my-pod 2/2 Running 0 35s
  • 常見問題
    • 為什麼需要在一個 Pod 中包含兩個容器
    • Pod 中有自己的網路,同一個 Pod 中的容器之間可以透過 localhost:port_num 互相溝通。而這樣無需透過外網的性質,讓我們可以將性質相近的服務放在同一個 Pod 裡,好比一個後端 API service,與一個後端認證 service,可以放在同一個 pod 裡互相溝通

Pod lifecycle 生命週期

0201lifecycle.png

Container state

  • waiting
  • Running
  • Termination
    • Process is terminated/crashed
    • Pod is deleted
    • Node failure or maintenance
    • Evicteed due to lack of resources

停止 / 刪除 Pods

kubectl delete pod $NAME

當執行刪除的時候,

  • API server會設定一個 timer(grace period Timer),預設是 30 秒
  • 同時 pod 狀態改成 Terminating
  • Pod 所在 node 上的 kubelet 收到指令,會給 Pod 裡的 container 傳送 SIGTERM 訊號,然後等等 container 退出
  • 如果 container 在 timer 到時之前退出了,那麼 pod 資訊同時會被 API server 從儲存中刪除
  • 如果 container 沒有在 timer 到時之前退出,則 kubelet 會發送 SIGKILL 資訊到 pod 裡的容器,強制殺死容器, 最後 API server 更新儲存 etcd

grace period timer 是可以修改的

kubectl delete pod $PODNAME --grace-period=<seconds>

或也可以直接就強制刪除 pod (SIGKILL)

kubectl delete pod $PODNAME --grace-period=0 --force

RestartPolicy

field with possible values AlwaysOnFailure, and Never. The default value is Always.

kubectl run web --image nginx --dry-run=client -o yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: web
name: web
spec:
containers:
- image: nginx
name: web
resources: {} dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}

kubectl dry-run

  • Server-side
    • 和正常情況一樣處理客戶端發送過來的請求,但不會把 Object 狀態持久化到 storage 中
kubectl apply -f nginx.yml --dry-run=server
  • Client-side
    • 把要操作的 Object 透過標準輸出 stdout 輸出到 terminal
    • 驗證 manifest 的語法
    • 可以用於產生語法正確的 Yaml manifest
kubectl apply -f nginx.yml --dry-run=client
kubectl run web --image=nginx --dry-run=client -o yaml
kubectl run web --image=nginx --dry-run=client -o yaml > nginx.yml

kubectl diff

顯示目前要部署的 manifest 和叢集中運行的有和不同,這樣就知道如果 apply 會發生什麼

diff -u -N /tmp/LIVE-4132877491/v1.Pod.default.web /tmp/MERGED-616947918/v1.Pod.default.web
--- /tmp/LIVE-4132877491/v1.Pod.default.web	2024-01-09 04:12:23.680171348 +0000
+++ /tmp/MERGED-616947918/v1.Pod.default.web 2024-01-09 04:12:23.680171348 +0000
@@ -11,7 +11,7 @@
uid: b00855d6-c3f0-46af-951c-8f5cfabbe3be
spec:
containers:
- - image: nginx:latest
+ - image: busybox
imagePullPolicy: Always
name: nginx-container
resources: {}

Pod的基本操作

  • 取得 pod 列表
kubectl get pods
NAME READY STATUS RESTARTS AGE
web 1/1 Running 0 118s
  • 刪除 pod
kubectl delete pod web
pod "web" deleted
  • 取得 pod 詳細信息
kubectl describe pod web
Name:             web
Namespace: default
Priority: 0
Service Account: default
Node: k8s-wrk-1/10.0.1.205
Start Time: Tue, 09 Jan 2024 04:16:41 +0000
Labels: <none>
Annotations: <none>
Status: Running
IP: 172.16.1.3
IPs:
IP: 172.16.1.3
Containers:
nginx-container:
Container ID: containerd://9a57f1f935fccc496967e4d6242581a8e8b10822aca1954f59175180ffe37ee8
Image: busybox
Image ID: docker.io/library/busybox@sha256:ba76950ac9eaa407512c9d859cea48114eeff8a6f12ebaa5d32ce79d4a017dd8
Port: <none>
Host Port: <none>
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: Tue, 09 Jan 2024 04:16:48 +0000
Finished: Tue, 09 Jan 2024 04:16:48 +0000
Ready: False
Restart Count: 1
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-sm8dr (ro)
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
kube-api-access-sm8dr:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 13s default-scheduler Successfully assigned default/web to k8s-wrk-1
Normal Pulled 8s kubelet Successfully pulled image "busybox" in 3.642s (3.642s including waiting)
Normal Pulling 7s (x2 over 12s) kubelet Pulling image "busybox"
Normal Created 6s (x2 over 8s) kubelet Created container nginx-container
Normal Started 6s (x2 over 8s) kubelet Started container nginx-container
Normal Pulled 6s kubelet Successfully pulled image "busybox" in 1.262s (1.262s including waiting)
Warning BackOff 4s (x2 over 5s) kubelet Back-off restarting failed container nginx-container in pod web_default(52450dde-88c7-4147-8dbe-f5d9955e6427)
  • 在容器中執行命令
kubectl exec web -- date
Tue Jan 9 04:20:21 UTC 2024
  • 進入容器的終端 terminal
kubectl exec web -it -- sh
  • 取得 pod 的 log
kubectl get pod web -v 5
kubectl get pod web -v 5
NAME READY STATUS RESTARTS AGE
web 1/1 Running 6 (2m30s ago) 5m31s
kubectl get pod web -v 6
kubectl get pod web -v 6
I0109 04:22:02.317263 19683 loader.go:395] Config loaded from file: /root/.kube/config
I0109 04:22:02.337673 19683 round_trippers.go:553] GET https://10.0.1.70:6443/api/v1/namespaces/default/pods/web 200 OK in 11 milliseconds
NAME READY STATUS RESTARTS AGE
web 1/1 Running 6 (2m20s ago) 5m21s
kubectl get pod web -v 7
kubectl get pod web -v 7
I0109 04:22:16.736715 19759 loader.go:395] Config loaded from file: /root/.kube/config
I0109 04:22:16.746590 19759 round_trippers.go:463] GET https://10.0.1.70:6443/api/v1/namespaces/default/pods/web
I0109 04:22:16.746846 19759 round_trippers.go:469] Request Headers:
I0109 04:22:16.746952 19759 round_trippers.go:473] Accept: application/json;as=Table;v=v1;[g=meta.k8s.io](http://g%3Dmeta.k8s.io/),application/json;as=Table;v=v1beta1;[g=meta.k8s.io](http://g%3Dmeta.k8s.io/),application/json
I0109 04:22:16.747073 19759 round_trippers.go:473] User-Agent: kubectl/v1.28.0 (linux/amd64) kubernetes/855e7c4
I0109 04:22:16.757450 19759 round_trippers.go:574] Response Status: 200 OK in 10 milliseconds

Init Containers

Init Container是運行於Pod Container之前的專用容器。Init Conatiner可以應用於一些不包含setup environment 的image

Init Container 與一般 Container 基本上完全一樣,有一點點不同的地方是,Init Container 和 Pod Container 不會同時存在於同一 Pod 中,Pod Container 會等待 Init Container 運行到完成狀態後才創建 每個初始化容器必須成功完成工作才能啟動下一個容器(包含初始化容器)。如果 Pod 的初始化容器失敗,Kubernetes 會反復重啟 Pod,直到初始化容器成功。但若 Pod 的參數--restart = Never,則 Kubernetes 不會重新啟動 Pod

initcontainers

  • why init containers
    • 初始化環境
    • 處理依賴控制啟動
apiVersion: v1
kind: Pod
metadata:
name: pod-with-init-containers
spec:
initContainers:
-name: init-service
image: busybox
command:["sh", "-c", "echo waiting for sercice; sleep 4"]-name: init-database
image: busybox
command:["sh", "-c", "echo waiting for database; sleep 4"]containers:-name: app-container
image: nginx

Static Pod 靜態 Pod

  • 由 Node 上的 kubelet 管理
  • 由 Static Pod manifests 宣告
    • staticPodPath in kubelet’s configuration, by default is /etc/kubernetes/manifests
  • kubelet configuration file
    • /var/lib/kubelet/config.yaml
  • pod can be ‘seen’ through API server, but can not be managed by API server

Control plane 上的 static pod

sudo ls /etc/kubernetes/manifests/
etcd.yaml kube-apiserver.yaml kube-controller-manager.yaml kube-scheduler.yaml

官方參考連結